library(here)
library(tidyverse)
library(conflicted)
# library(easystats)

exoplanets <- read_csv(here("data", "exoplanet_catalog_080325.csv"))
Warning: One or more parsing issues, call `problems()` on your data frame for details, e.g.:
  dat <- vroom(...)
  problems(dat)Rows: 7418 Columns: 98── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (12): name, planet_status, publication, detection_type, mass_measurement_type, radius_measurement_type, alternate_names, molecules, star_name, star_sp_ty...
dbl  (83): mass, mass_error_min, mass_error_max, mass_sini, mass_sini_error_min, mass_sini_error_max, radius, radius_error_min, radius_error_max, orbital_peri...
lgl   (2): hot_point_lon, star_magnetic_field
date  (1): updated
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
exoplanets
library(skimr)
skim(exoplanets)
Warning: There was 1 warning in `dplyr::summarize()`.
ℹ In argument: `dplyr::across(tidyselect::any_of(variable_names), mangled_skimmers$funs)`.
ℹ In group 0: .
Caused by warning:
! There was 1 warning in `dplyr::summarize()`.
ℹ In argument: `dplyr::across(tidyselect::any_of(variable_names), mangled_skimmers$funs)`.
Caused by warning in `inline_hist()`:
! Variable contains Inf or -Inf value(s) that were converted to NA.
── Data Summary ────────────────────────
                           Values    
Name                       exoplanets
Number of rows             7418      
Number of columns          98        
_______________________              
Column type frequency:               
  character                12        
  Date                     1         
  logical                  2         
  numeric                  83        
________________________             
Group variables            None      
library(naniar)
gg_miss_var(exoplanets)

library(visdat)
vis_dat(exoplanets)

names(exoplanets)
 [1] "name"                       "planet_status"              "mass"                       "mass_error_min"             "mass_error_max"            
 [6] "mass_sini"                  "mass_sini_error_min"        "mass_sini_error_max"        "radius"                     "radius_error_min"          
[11] "radius_error_max"           "orbital_period"             "orbital_period_error_min"   "orbital_period_error_max"   "semi_major_axis"           
[16] "semi_major_axis_error_min"  "semi_major_axis_error_max"  "eccentricity"               "eccentricity_error_min"     "eccentricity_error_max"    
[21] "inclination"                "inclination_error_min"      "inclination_error_max"      "angular_distance"           "discovered"                
[26] "updated"                    "omega"                      "omega_error_min"            "omega_error_max"            "tperi"                     
[31] "tperi_error_min"            "tperi_error_max"            "tconj"                      "tconj_error_min"            "tconj_error_max"           
[36] "tzero_tr"                   "tzero_tr_error_min"         "tzero_tr_error_max"         "tzero_tr_sec"               "tzero_tr_sec_error_min"    
[41] "tzero_tr_sec_error_max"     "lambda_angle"               "lambda_angle_error_min"     "lambda_angle_error_max"     "impact_parameter"          
[46] "impact_parameter_error_min" "impact_parameter_error_max" "tzero_vr"                   "tzero_vr_error_min"         "tzero_vr_error_max"        
[51] "k"                          "k_error_min"                "k_error_max"                "temp_calculated"            "temp_calculated_error_min" 
[56] "temp_calculated_error_max"  "temp_measured"              "hot_point_lon"              "geometric_albedo"           "geometric_albedo_error_min"
[61] "geometric_albedo_error_max" "log_g"                      "publication"                "detection_type"             "mass_measurement_type"     
[66] "radius_measurement_type"    "alternate_names"            "molecules"                  "star_name"                  "ra"                        
[71] "dec"                        "mag_v"                      "mag_i"                      "mag_j"                      "mag_h"                     
[76] "mag_k"                      "star_distance"              "star_distance_error_min"    "star_distance_error_max"    "star_metallicity"          
[81] "star_metallicity_error_min" "star_metallicity_error_max" "star_mass"                  "star_mass_error_min"        "star_mass_error_max"       
[86] "star_radius"                "star_radius_error_min"      "star_radius_error_max"      "star_sp_type"               "star_age"                  
[91] "star_age_error_min"         "star_age_error_max"         "star_teff"                  "star_teff_error_min"        "star_teff_error_max"       
[96] "star_detected_disc"         "star_magnetic_field"        "star_alternate_names"      
library(janitor)
exoplanets %>% tabyl(planet_status)
 planet_status    n percent
     Confirmed 7418       1
library(data.table)
# options(repr.matrix.max.rows=100)
exoplanets %>% 
  add_prop_miss() %>%
  arrange(prop_miss_all) %>% 
  head(5) %>% 
  data.table::transpose(keep.names="column") -> preview

preview
# preview %>% View()

We have a lot of features: - Planet name - Mass (M jup) - Mass*sin(i) (M jup) - This describes minimum mass of the planet due to inclination effect - Radius (Rjup) - Period (day) - a / the average distance of the planet and its star - it’s in AU (astronomical units), which is the standard distance used for these types of things - 1 AU is the average distance tween the earth and the sun - e / eccentry of a planet (between 0 and 1) - represenets how much of a circle is the orbit - e = 0 means perfect circle, e > 1 means its not bound to the star - Discovery - year when it was discovered - update - year it was updated -

conflicts_prefer(dplyr::filter)
[conflicted] Removing existing preference.[conflicted] Will prefer dplyr::filter over any other package.
exoplanets %>% 
  filter(name %>% str_like("%TOI-784%"))
conflicts_prefer(dplyr::filter)
[conflicted] Removing existing preference.[conflicted] Will prefer dplyr::filter over any other package.
exoplanets %>% 
  filter(discovered == 2023)
exoplanets %>%
  mutate(
    ra_rad = ra,  # Convert RA to radians
    dec_rad = dec  # Convert Dec to radians
  ) %>% 
  ggplot(aes(x = ra_rad, y = dec_rad, color = dec)) +
  geom_point(size = 0.4) +
  coord_map("aitoff") +  # Apply Aitoff projection
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "none"  # Optionally remove legend
  )

# check columsn that start with star
exoplanets %>% 
  select(starts_with("star"))
library(dplyr)
library(plotly)

# Create a new column to distinguish Kepler exoplanets
exoplanets_3d <- exoplanets %>%
  mutate(
    ra_rad = ra * pi / 180,   # Convert RA from degrees to radians
    dec_rad = dec * pi / 180, # Convert Dec from degrees to radians
    x = cos(dec_rad) * cos(ra_rad), # Convert to Cartesian coordinates
    y = cos(dec_rad) * sin(ra_rad),
    z = sin(dec_rad),
    color = case_when(  # Create a column for red when kepler, blue otherwise
      str_detect(paste(name, alternate_names), regex("kepler|koi", ignore_case = TRUE)) ~ "Kepler",
      # if it's free floating (star_name is NA)
      star_name %>% is.na() ~ "Free Floating",
      TRUE ~ "Other"
    ),
    hover_text = paste("Name: ", name) # Create custom hover text with the name of the exoplanet
  )

# Define steps for opacity slider
steps <- list(
  list(args = list("marker.opacity", 0.0), label = "0.0", method = "restyle"),
  list(args = list("marker.opacity", 0.1), label = "0.1", method = "restyle"),
  list(args = list("marker.opacity", 0.2), label = "0.2", method = "restyle"),
  list(args = list("marker.opacity", 0.3), label = "0.3", method = "restyle"),
  list(args = list("marker.opacity", 0.4), label = "0.4", method = "restyle"),
  list(args = list("marker.opacity", 0.5), label = "0.5", method = "restyle"),
  list(args = list("marker.opacity", 0.6), label = "0.6", method = "restyle"),
  list(args = list("marker.opacity", 0.7), label = "0.7", method = "restyle"),
  list(args = list("marker.opacity", 0.8), label = "0.8", method = "restyle"),
  list(args = list("marker.opacity", 0.9), label = "0.9", method = "restyle"),
  list(args = list("marker.opacity", 1.0), label = "1.0", method = "restyle")
)

# Create an interactive 3D scatter plot with plotly
plot_ly(
  data = exoplanets_3d,
  x = ~x,
  y = ~y,
  z = ~z,
  color = ~color,  # Use the kepler_highlight column for color mapping
  colors = c("Other" = "red", "Kepler" = "blue", "Free Floating" = "green"),
  text = ~hover_text, # Show the name of the exoplanet on hover
  type = "scatter3d",
  mode = "markers",
  marker = list(size = 1, opacity = 0.7), # Default opacity
  showlegend = TRUE
) %>%
  layout(
    title = "3D Sky Map of Exoplanets (Kepler Highlighted)",
    scene = list(
      xaxis = list(title = "X"),
      yaxis = list(title = "Y"),
      zaxis = list(title = "Z")
    ),
    sliders = list(
      list(
        active = 1,  # Set the default opacity value to 1.0 (fully opaque)
        currentvalue = list(
          prefix = "Opacity: ",
          font = list(size = 15)
        ),
        pad = list(t = 60),
        steps = steps  # Use the steps defined earlier for the opacity slider
      )
    )
  )
Warning: Ignoring 1 observationsWarning: Ignoring 1 observations

# Assuming your data is loaded as 'exoplanets'
# Convert RA to degrees (if it's in hours:minutes:seconds format)
# If RA is already in degrees, skip this step
exoplanets %>%
  mutate(
    ra_deg = ra,  # Convert RA from hours to degrees (if needed)
    # Convert to polar coordinates for plotting
    # RA is mapped to theta (0-360 degrees)
    theta = ra_deg
  ) %>% 
ggplot(aes(x = theta, y = star_distance, color = mass)) +
  # Use coord_polar for circular plot
  coord_polar(start = 0, direction = -1) + # Start at 0 degrees, clockwise direction
  # Add concentric circles for distance reference
  geom_hline(yintercept = c(10, 100, 1000, 10000), 
             color = "gray", linetype = "solid", size = 0.3, alpha = 0.7) +
  # Add radial lines for angle reference
  geom_vline(xintercept = seq(0, 330, by = 30), 
             color = "gray", linetype = "solid", size = 0.3, alpha = 0.7) +
  # Plot the exoplanets
  geom_point(alpha = 0.8, size = 1) +
  # Use log scale for distance
  scale_y_log10(
    breaks = c(10, 100, 1000, 10000),
    labels = c("10 pc", "100 pc", "1000 pc", "10000 pc"),
    limits = c(1, 15000)
  ) +
  # Use log scale for mass colors
  scale_color_gradientn(
    colors = c("#1E90FF", "#32CD32", "#FFFF00", "#FFA500", "#FF4500", "#FF0000"),
    trans = "log10",
    breaks = c(0.0001, 0.001, 0.01, 0.1, 1, 10),
    labels = c("10⁻⁴", "10⁻³", "10⁻²", "10⁻¹", "10⁰", "10¹"),
    name = "Planetary Mass (MJup)"
  ) +
  # Remove grid and axis elements
  theme_minimal() +
  theme(
    axis.title = element_blank(),
    axis.text.y = element_blank(),
    axis.text.x = element_blank(),
    panel.grid = element_blank(),
    legend.position = "bottom",
    legend.box = "horizontal",
    plot.title = element_text(hjust = 0.5)
  ) +
  ggtitle("Exoplanet Distribution")

library(dplyr)
library(plotly)

# Create a new column to distinguish Kepler exoplanets
exoplanets_3d <- exoplanets %>%
  mutate(
    ra_rad = ra * pi / 180,   # Convert RA from degrees to radians
    dec_rad = dec * pi / 180, # Convert Dec from degrees to radians
    x = cos(dec_rad) * cos(ra_rad), # Convert to Cartesian coordinates
    y = cos(dec_rad) * sin(ra_rad),
    z = sin(dec_rad),
    color = case_when(  # Create a column for red when kepler, blue otherwise
      str_detect(paste(name, alternate_names), regex("kepler|koi", ignore_case = TRUE)) ~ "Kepler",
      # if it's free floating (star_name is NA)
      star_name %>% is.na() ~ "Free Floating",
      TRUE ~ "Other"
    ),
    hover_text = paste("Name: ", name), # Create custom hover text with the name of the exoplanet
    scaled_x = x * (1 / star_distance),  # Adjust x coordinate by star distance (closer = closer to center)
    scaled_y = y * (1 / star_distance),  # Adjust y coordinate similarly
    scaled_z = z * (1 / star_distance)   # Adjust z coordinate similarly
  )

# Define steps for opacity slider
steps <- list(
  list(args = list("marker.opacity", 0.0), label = "0.0", method = "restyle"),
  list(args = list("marker.opacity", 0.1), label = "0.1", method = "restyle"),
  list(args = list("marker.opacity", 0.2), label = "0.2", method = "restyle"),
  list(args = list("marker.opacity", 0.3), label = "0.3", method = "restyle"),
  list(args = list("marker.opacity", 0.4), label = "0.4", method = "restyle"),
  list(args = list("marker.opacity", 0.5), label = "0.5", method = "restyle"),
  list(args = list("marker.opacity", 0.6), label = "0.6", method = "restyle"),
  list(args = list("marker.opacity", 0.7), label = "0.7", method = "restyle"),
  list(args = list("marker.opacity", 0.8), label = "0.8", method = "restyle"),
  list(args = list("marker.opacity", 0.9), label = "0.9", method = "restyle"),
  list(args = list("marker.opacity", 1.0), label = "1.0", method = "restyle")
)

# Create an interactive 3D scatter plot with plotly
fig <- plot_ly(
  data = exoplanets_3d,
  x = ~scaled_x,
  y = ~scaled_y,
  z = ~scaled_z,
  color = ~color,  # Use the kepler_highlight column for color mapping
  colors = c("Other" = "red", "Kepler" = "blue", "Free Floating" = "green"),
  text = ~hover_text, # Show the name of the exoplanet on hover
  type = "scatter3d",
  mode = "markers",
  marker = list(size = 2, opacity = 0.7), # Default opacity
  showlegend = TRUE
)

# Add layout with a slider for opacity
fig <- fig %>% layout(
  title = "3D Sky Map of Exoplanets (Kepler Highlighted)",
  scene = list(
    xaxis = list(title = "X"),
    yaxis = list(title = "Y"),
    zaxis = list(title = "Z")
  ),
  sliders = list(
    list(
      active = 1,  # Set the default opacity value to 1.0 (fully opaque)
      currentvalue = list(
        prefix = "Opacity: ",
        font = list(size = 15)
      ),
      pad = list(t = 60),
      steps = steps  # Use the steps defined earlier for the opacity slider
    )
  )
)

fig
Warning: Ignoring 357 observationsWarning: Ignoring 357 observations
exoplanets %>% names()
 [1] "name"                       "planet_status"              "mass"                       "mass_error_min"             "mass_error_max"            
 [6] "mass_sini"                  "mass_sini_error_min"        "mass_sini_error_max"        "radius"                     "radius_error_min"          
[11] "radius_error_max"           "orbital_period"             "orbital_period_error_min"   "orbital_period_error_max"   "semi_major_axis"           
[16] "semi_major_axis_error_min"  "semi_major_axis_error_max"  "eccentricity"               "eccentricity_error_min"     "eccentricity_error_max"    
[21] "inclination"                "inclination_error_min"      "inclination_error_max"      "angular_distance"           "discovered"                
[26] "updated"                    "omega"                      "omega_error_min"            "omega_error_max"            "tperi"                     
[31] "tperi_error_min"            "tperi_error_max"            "tconj"                      "tconj_error_min"            "tconj_error_max"           
[36] "tzero_tr"                   "tzero_tr_error_min"         "tzero_tr_error_max"         "tzero_tr_sec"               "tzero_tr_sec_error_min"    
[41] "tzero_tr_sec_error_max"     "lambda_angle"               "lambda_angle_error_min"     "lambda_angle_error_max"     "impact_parameter"          
[46] "impact_parameter_error_min" "impact_parameter_error_max" "tzero_vr"                   "tzero_vr_error_min"         "tzero_vr_error_max"        
[51] "k"                          "k_error_min"                "k_error_max"                "temp_calculated"            "temp_calculated_error_min" 
[56] "temp_calculated_error_max"  "temp_measured"              "hot_point_lon"              "geometric_albedo"           "geometric_albedo_error_min"
[61] "geometric_albedo_error_max" "log_g"                      "publication"                "detection_type"             "mass_measurement_type"     
[66] "radius_measurement_type"    "alternate_names"            "molecules"                  "star_name"                  "ra"                        
[71] "dec"                        "mag_v"                      "mag_i"                      "mag_j"                      "mag_h"                     
[76] "mag_k"                      "star_distance"              "star_distance_error_min"    "star_distance_error_max"    "star_metallicity"          
[81] "star_metallicity_error_min" "star_metallicity_error_max" "star_mass"                  "star_mass_error_min"        "star_mass_error_max"       
[86] "star_radius"                "star_radius_error_min"      "star_radius_error_max"      "star_sp_type"               "star_age"                  
[91] "star_age_error_min"         "star_age_error_max"         "star_teff"                  "star_teff_error_min"        "star_teff_error_max"       
[96] "star_detected_disc"         "star_magnetic_field"        "star_alternate_names"      
# check how many are missing
exoplanets %>% 
  select(ra, dec, angular_distance) %>% 
  mutate(ra = ra %>% is.na(), dec = dec %>% is.na(), angular_distance = angular_distance %>% is.na()) %>%
  summarise_all(mean) %>%
  gather(key="column", value="percentage")
# check which ones dont have ra
exoplanets %>% 
  filter(ra %>% is.na())
# check out alternate names
exoplanets %>% 
  select(name, alternate_names) %>% 
  filter(alternate_names %>% str_length() > 0)
NA
exoplanets %>% 
  tabyl(publication)
                            publication    n     percent
 Announced on a professional conference   55 0.007414397
                 Announced on a website 2357 0.317740631
          Published in a refereed paper 4873 0.656915611
    Submitted to a professional journal  133 0.017929361
# remove any column with error in the name
exoplanets_r <- exoplanets %>% 
  select(-contains("error")) %>% 
  select(-planet_status, -updated, -alternate_names, -publication) %>% # useless
  select(-hot_point_lon, ) # too many missings
exoplanets_r %>% names
library(visdat)
vis_dat(exoplanets_r)
vis_miss(exoplanets_r, sort_miss = T, cluster = T)

detection type

exoplanets %>% 
  tabyl("detection_type") %>% 
  arrange(-n)
library(fastDummies)
exoplanets_rd <- exoplanets_r %>% 
  dummy_cols(select_columns = "detection_type", split = ", ") %>% 
  # make them bools
  mutate_at(vars(starts_with("detection_type_")), as.logical)
exoplanets_rd %>% select(starts_with("detection_type")) %>% 
  unique
library(naniar)
exoplanets_rd %>%
  group_by(`detection_type_Primary Transit`) %>% 
  miss_var_summary() %>% 
  arrange(variable) %>% 
  filter(variable %>% str_detect("detection_type", negate = T)) %>% 
  ggplot(aes(x = variable, y = pct_miss, fill = `detection_type_Primary Transit`)) +
  geom_col(position="dodge") +
  coord_flip() 

Kepler

# filter by the kepler
exoplanets %>% 
  filter(name %>% str_like("%Kepler%")) %>% 
  tabyl("detection_type")
# check other
exoplanets %>% 
  filter(detection_type == "Other")
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7cn0NCmxpYnJhcnkoaGVyZSkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShjb25mbGljdGVkKQ0KIyBsaWJyYXJ5KGVhc3lzdGF0cykNCg0KZXhvcGxhbmV0cyA8LSByZWFkX2NzdihoZXJlKCJkYXRhIiwgImV4b3BsYW5ldF9jYXRhbG9nXzA4MDMyNS5jc3YiKSkNCmV4b3BsYW5ldHMNCmBgYA0KDQoNCmBgYHtyfQ0KbGlicmFyeShza2ltcikNCnNraW0oZXhvcGxhbmV0cykNCmBgYA0KDQoNCmBgYHtyLGZpZy5hc3A9Mn0NCmxpYnJhcnkobmFuaWFyKQ0KZ2dfbWlzc192YXIoZXhvcGxhbmV0cykNCmBgYA0KDQoNCmBgYHtyLCBmaWcud2lkdGg9MjAsIGZpZy5oZWlnaHQ9MTB9DQpsaWJyYXJ5KHZpc2RhdCkNCnZpc19kYXQoZXhvcGxhbmV0cykNCmBgYA0KDQoNCmBgYHtyfQ0KbmFtZXMoZXhvcGxhbmV0cykNCmBgYA0KDQoNCmBgYHtyfQ0KbGlicmFyeShqYW5pdG9yKQ0KZXhvcGxhbmV0cyAlPiUgdGFieWwocGxhbmV0X3N0YXR1cykNCmBgYA0KDQoNCmBgYHtyfQ0KbGlicmFyeShkYXRhLnRhYmxlKQ0KIyBvcHRpb25zKHJlcHIubWF0cml4Lm1heC5yb3dzPTEwMCkNCmV4b3BsYW5ldHMgJT4lIA0KICBhZGRfcHJvcF9taXNzKCkgJT4lDQogIGFycmFuZ2UocHJvcF9taXNzX2FsbCkgJT4lIA0KICBoZWFkKDUpICU+JSANCiAgZGF0YS50YWJsZTo6dHJhbnNwb3NlKGtlZXAubmFtZXM9ImNvbHVtbiIpIC0+IHByZXZpZXcNCg0KcHJldmlldw0KIyBwcmV2aWV3ICU+JSBWaWV3KCkNCmBgYA0KDQpXZSBoYXZlIGEgbG90IG9mIGZlYXR1cmVzOg0KLSBQbGFuZXQgbmFtZQ0KLSBNYXNzIChNIGp1cCkNCi0gTWFzcypzaW4oaSkgKE0ganVwKQ0KICAtIFRoaXMgZGVzY3JpYmVzIG1pbmltdW0gbWFzcyBvZiB0aGUgcGxhbmV0IGR1ZSB0byBpbmNsaW5hdGlvbiBlZmZlY3QNCi0gUmFkaXVzIChSanVwKQ0KLSBQZXJpb2QgKGRheSkNCi0gYSAvIHRoZSBhdmVyYWdlIGRpc3RhbmNlIG9mIHRoZSBwbGFuZXQgYW5kIGl0cyBzdGFyDQogIC0gaXQncyBpbiBBVSAoYXN0cm9ub21pY2FsIHVuaXRzKSwgd2hpY2ggaXMgdGhlIHN0YW5kYXJkIGRpc3RhbmNlIHVzZWQgZm9yIHRoZXNlIHR5cGVzIG9mIHRoaW5ncw0KICAtIDEgQVUgaXMgdGhlIGF2ZXJhZ2UgZGlzdGFuY2UgdHdlZW4gdGhlIGVhcnRoIGFuZCB0aGUgc3VuDQotIGUgLyBlY2NlbnRyeSBvZiBhIHBsYW5ldCAoYmV0d2VlbiAwIGFuZCAxKQ0KICAtIHJlcHJlc2VuZXRzIGhvdyBtdWNoIG9mIGEgY2lyY2xlIGlzIHRoZSBvcmJpdA0KICAtIGUgPSAwIG1lYW5zIHBlcmZlY3QgY2lyY2xlLCBlID4gMSBtZWFucyBpdHMgbm90IGJvdW5kIHRvIHRoZSBzdGFyDQotIERpc2NvdmVyeSAtIHllYXIgd2hlbiBpdCB3YXMgZGlzY292ZXJlZA0KLSB1cGRhdGUgLSB5ZWFyIGl0IHdhcyB1cGRhdGVkDQotIA0KDQpgYGB7cn0NCmNvbmZsaWN0c19wcmVmZXIoZHBseXI6OmZpbHRlcikNCmV4b3BsYW5ldHMgJT4lIA0KICBmaWx0ZXIobmFtZSAlPiUgc3RyX2xpa2UoIiVUT0ktNzg0JSIpKQ0KYGBgDQoNCg0KYGBge3J9DQpjb25mbGljdHNfcHJlZmVyKGRwbHlyOjpmaWx0ZXIpDQpleG9wbGFuZXRzICU+JSANCiAgZmlsdGVyKGRpc2NvdmVyZWQgPT0gMjAyMykNCmBgYA0KDQpgYGB7cn0NCmV4b3BsYW5ldHMgJT4lDQogIG11dGF0ZSgNCiAgICByYV9yYWQgPSByYSwgICMgQ29udmVydCBSQSB0byByYWRpYW5zDQogICAgZGVjX3JhZCA9IGRlYyAgIyBDb252ZXJ0IERlYyB0byByYWRpYW5zDQogICkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSByYV9yYWQsIHkgPSBkZWNfcmFkLCBjb2xvciA9IGRlYykpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMC40KSArDQogIGNvb3JkX21hcCgiYWl0b2ZmIikgKyAgIyBBcHBseSBBaXRvZmYgcHJvamVjdGlvbg0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZSgNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiAgIyBPcHRpb25hbGx5IHJlbW92ZSBsZWdlbmQNCiAgKQ0KYGBgDQoNCg0KYGBge3J9DQojIGNoZWNrIGNvbHVtc24gdGhhdCBzdGFydCB3aXRoIHN0YXINCmV4b3BsYW5ldHMgJT4lIA0KICBzZWxlY3Qoc3RhcnRzX3dpdGgoInN0YXIiKSkNCmBgYA0KDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocGxvdGx5KQ0KDQojIENyZWF0ZSBhIG5ldyBjb2x1bW4gdG8gZGlzdGluZ3Vpc2ggS2VwbGVyIGV4b3BsYW5ldHMNCmV4b3BsYW5ldHNfM2QgPC0gZXhvcGxhbmV0cyAlPiUNCiAgbXV0YXRlKA0KICAgIHJhX3JhZCA9IHJhICogcGkgLyAxODAsICAgIyBDb252ZXJ0IFJBIGZyb20gZGVncmVlcyB0byByYWRpYW5zDQogICAgZGVjX3JhZCA9IGRlYyAqIHBpIC8gMTgwLCAjIENvbnZlcnQgRGVjIGZyb20gZGVncmVlcyB0byByYWRpYW5zDQogICAgeCA9IGNvcyhkZWNfcmFkKSAqIGNvcyhyYV9yYWQpLCAjIENvbnZlcnQgdG8gQ2FydGVzaWFuIGNvb3JkaW5hdGVzDQogICAgeSA9IGNvcyhkZWNfcmFkKSAqIHNpbihyYV9yYWQpLA0KICAgIHogPSBzaW4oZGVjX3JhZCksDQogICAgY29sb3IgPSBjYXNlX3doZW4oICAjIENyZWF0ZSBhIGNvbHVtbiBmb3IgcmVkIHdoZW4ga2VwbGVyLCBibHVlIG90aGVyd2lzZQ0KICAgICAgc3RyX2RldGVjdChwYXN0ZShuYW1lLCBhbHRlcm5hdGVfbmFtZXMpLCByZWdleCgia2VwbGVyfGtvaSIsIGlnbm9yZV9jYXNlID0gVFJVRSkpIH4gIktlcGxlciIsDQogICAgICAjIGlmIGl0J3MgZnJlZSBmbG9hdGluZyAoc3Rhcl9uYW1lIGlzIE5BKQ0KICAgICAgc3Rhcl9uYW1lICU+JSBpcy5uYSgpIH4gIkZyZWUgRmxvYXRpbmciLA0KICAgICAgVFJVRSB+ICJPdGhlciINCiAgICApLA0KICAgIGhvdmVyX3RleHQgPSBwYXN0ZSgiTmFtZTogIiwgbmFtZSkgIyBDcmVhdGUgY3VzdG9tIGhvdmVyIHRleHQgd2l0aCB0aGUgbmFtZSBvZiB0aGUgZXhvcGxhbmV0DQogICkNCg0KIyBEZWZpbmUgc3RlcHMgZm9yIG9wYWNpdHkgc2xpZGVyDQpzdGVwcyA8LSBsaXN0KA0KICBsaXN0KGFyZ3MgPSBsaXN0KCJtYXJrZXIub3BhY2l0eSIsIDAuMCksIGxhYmVsID0gIjAuMCIsIG1ldGhvZCA9ICJyZXN0eWxlIiksDQogIGxpc3QoYXJncyA9IGxpc3QoIm1hcmtlci5vcGFjaXR5IiwgMC4xKSwgbGFiZWwgPSAiMC4xIiwgbWV0aG9kID0gInJlc3R5bGUiKSwNCiAgbGlzdChhcmdzID0gbGlzdCgibWFya2VyLm9wYWNpdHkiLCAwLjIpLCBsYWJlbCA9ICIwLjIiLCBtZXRob2QgPSAicmVzdHlsZSIpLA0KICBsaXN0KGFyZ3MgPSBsaXN0KCJtYXJrZXIub3BhY2l0eSIsIDAuMyksIGxhYmVsID0gIjAuMyIsIG1ldGhvZCA9ICJyZXN0eWxlIiksDQogIGxpc3QoYXJncyA9IGxpc3QoIm1hcmtlci5vcGFjaXR5IiwgMC40KSwgbGFiZWwgPSAiMC40IiwgbWV0aG9kID0gInJlc3R5bGUiKSwNCiAgbGlzdChhcmdzID0gbGlzdCgibWFya2VyLm9wYWNpdHkiLCAwLjUpLCBsYWJlbCA9ICIwLjUiLCBtZXRob2QgPSAicmVzdHlsZSIpLA0KICBsaXN0KGFyZ3MgPSBsaXN0KCJtYXJrZXIub3BhY2l0eSIsIDAuNiksIGxhYmVsID0gIjAuNiIsIG1ldGhvZCA9ICJyZXN0eWxlIiksDQogIGxpc3QoYXJncyA9IGxpc3QoIm1hcmtlci5vcGFjaXR5IiwgMC43KSwgbGFiZWwgPSAiMC43IiwgbWV0aG9kID0gInJlc3R5bGUiKSwNCiAgbGlzdChhcmdzID0gbGlzdCgibWFya2VyLm9wYWNpdHkiLCAwLjgpLCBsYWJlbCA9ICIwLjgiLCBtZXRob2QgPSAicmVzdHlsZSIpLA0KICBsaXN0KGFyZ3MgPSBsaXN0KCJtYXJrZXIub3BhY2l0eSIsIDAuOSksIGxhYmVsID0gIjAuOSIsIG1ldGhvZCA9ICJyZXN0eWxlIiksDQogIGxpc3QoYXJncyA9IGxpc3QoIm1hcmtlci5vcGFjaXR5IiwgMS4wKSwgbGFiZWwgPSAiMS4wIiwgbWV0aG9kID0gInJlc3R5bGUiKQ0KKQ0KDQojIENyZWF0ZSBhbiBpbnRlcmFjdGl2ZSAzRCBzY2F0dGVyIHBsb3Qgd2l0aCBwbG90bHkNCnBsb3RfbHkoDQogIGRhdGEgPSBleG9wbGFuZXRzXzNkLA0KICB4ID0gfngsDQogIHkgPSB+eSwNCiAgeiA9IH56LA0KICBjb2xvciA9IH5jb2xvciwgICMgVXNlIHRoZSBrZXBsZXJfaGlnaGxpZ2h0IGNvbHVtbiBmb3IgY29sb3IgbWFwcGluZw0KICBjb2xvcnMgPSBjKCJPdGhlciIgPSAicmVkIiwgIktlcGxlciIgPSAiYmx1ZSIsICJGcmVlIEZsb2F0aW5nIiA9ICJncmVlbiIpLA0KICB0ZXh0ID0gfmhvdmVyX3RleHQsICMgU2hvdyB0aGUgbmFtZSBvZiB0aGUgZXhvcGxhbmV0IG9uIGhvdmVyDQogIHR5cGUgPSAic2NhdHRlcjNkIiwNCiAgbW9kZSA9ICJtYXJrZXJzIiwNCiAgbWFya2VyID0gbGlzdChzaXplID0gMSwgb3BhY2l0eSA9IDAuNyksICMgRGVmYXVsdCBvcGFjaXR5DQogIHNob3dsZWdlbmQgPSBUUlVFDQopICU+JQ0KICBsYXlvdXQoDQogICAgdGl0bGUgPSAiM0QgU2t5IE1hcCBvZiBFeG9wbGFuZXRzIChLZXBsZXIgSGlnaGxpZ2h0ZWQpIiwNCiAgICBzY2VuZSA9IGxpc3QoDQogICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiWCIpLA0KICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlkiKSwNCiAgICAgIHpheGlzID0gbGlzdCh0aXRsZSA9ICJaIikNCiAgICApLA0KICAgIHNsaWRlcnMgPSBsaXN0KA0KICAgICAgbGlzdCgNCiAgICAgICAgYWN0aXZlID0gMSwgICMgU2V0IHRoZSBkZWZhdWx0IG9wYWNpdHkgdmFsdWUgdG8gMS4wIChmdWxseSBvcGFxdWUpDQogICAgICAgIGN1cnJlbnR2YWx1ZSA9IGxpc3QoDQogICAgICAgICAgcHJlZml4ID0gIk9wYWNpdHk6ICIsDQogICAgICAgICAgZm9udCA9IGxpc3Qoc2l6ZSA9IDE1KQ0KICAgICAgICApLA0KICAgICAgICBwYWQgPSBsaXN0KHQgPSA2MCksDQogICAgICAgIHN0ZXBzID0gc3RlcHMgICMgVXNlIHRoZSBzdGVwcyBkZWZpbmVkIGVhcmxpZXIgZm9yIHRoZSBvcGFjaXR5IHNsaWRlcg0KICAgICAgKQ0KICAgICkNCiAgKQ0KDQpgYGANCg0KYGBge3J9DQoNCiMgQXNzdW1pbmcgeW91ciBkYXRhIGlzIGxvYWRlZCBhcyAnZXhvcGxhbmV0cycNCiMgQ29udmVydCBSQSB0byBkZWdyZWVzIChpZiBpdCdzIGluIGhvdXJzOm1pbnV0ZXM6c2Vjb25kcyBmb3JtYXQpDQojIElmIFJBIGlzIGFscmVhZHkgaW4gZGVncmVlcywgc2tpcCB0aGlzIHN0ZXANCmV4b3BsYW5ldHMgJT4lDQogIG11dGF0ZSgNCiAgICByYV9kZWcgPSByYSwgICMgQ29udmVydCBSQSBmcm9tIGhvdXJzIHRvIGRlZ3JlZXMgKGlmIG5lZWRlZCkNCiAgICAjIENvbnZlcnQgdG8gcG9sYXIgY29vcmRpbmF0ZXMgZm9yIHBsb3R0aW5nDQogICAgIyBSQSBpcyBtYXBwZWQgdG8gdGhldGEgKDAtMzYwIGRlZ3JlZXMpDQogICAgdGhldGEgPSByYV9kZWcNCiAgKSAlPiUgDQpnZ3Bsb3QoYWVzKHggPSB0aGV0YSwgeSA9IHN0YXJfZGlzdGFuY2UsIGNvbG9yID0gbWFzcykpICsNCiAgIyBVc2UgY29vcmRfcG9sYXIgZm9yIGNpcmN1bGFyIHBsb3QNCiAgY29vcmRfcG9sYXIoc3RhcnQgPSAwLCBkaXJlY3Rpb24gPSAtMSkgKyAjIFN0YXJ0IGF0IDAgZGVncmVlcywgY2xvY2t3aXNlIGRpcmVjdGlvbg0KICAjIEFkZCBjb25jZW50cmljIGNpcmNsZXMgZm9yIGRpc3RhbmNlIHJlZmVyZW5jZQ0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBjKDEwLCAxMDAsIDEwMDAsIDEwMDAwKSwgDQogICAgICAgICAgICAgY29sb3IgPSAiZ3JheSIsIGxpbmV0eXBlID0gInNvbGlkIiwgc2l6ZSA9IDAuMywgYWxwaGEgPSAwLjcpICsNCiAgIyBBZGQgcmFkaWFsIGxpbmVzIGZvciBhbmdsZSByZWZlcmVuY2UNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gc2VxKDAsIDMzMCwgYnkgPSAzMCksIA0KICAgICAgICAgICAgIGNvbG9yID0gImdyYXkiLCBsaW5ldHlwZSA9ICJzb2xpZCIsIHNpemUgPSAwLjMsIGFscGhhID0gMC43KSArDQogICMgUGxvdCB0aGUgZXhvcGxhbmV0cw0KICBnZW9tX3BvaW50KGFscGhhID0gMC44LCBzaXplID0gMSkgKw0KICAjIFVzZSBsb2cgc2NhbGUgZm9yIGRpc3RhbmNlDQogIHNjYWxlX3lfbG9nMTAoDQogICAgYnJlYWtzID0gYygxMCwgMTAwLCAxMDAwLCAxMDAwMCksDQogICAgbGFiZWxzID0gYygiMTAgcGMiLCAiMTAwIHBjIiwgIjEwMDAgcGMiLCAiMTAwMDAgcGMiKSwNCiAgICBsaW1pdHMgPSBjKDEsIDE1MDAwKQ0KICApICsNCiAgIyBVc2UgbG9nIHNjYWxlIGZvciBtYXNzIGNvbG9ycw0KICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oDQogICAgY29sb3JzID0gYygiIzFFOTBGRiIsICIjMzJDRDMyIiwgIiNGRkZGMDAiLCAiI0ZGQTUwMCIsICIjRkY0NTAwIiwgIiNGRjAwMDAiKSwNCiAgICB0cmFucyA9ICJsb2cxMCIsDQogICAgYnJlYWtzID0gYygwLjAwMDEsIDAuMDAxLCAwLjAxLCAwLjEsIDEsIDEwKSwNCiAgICBsYWJlbHMgPSBjKCIxMOKBu+KBtCIsICIxMOKBu8KzIiwgIjEw4oG7wrIiLCAiMTDigbvCuSIsICIxMOKBsCIsICIxMMK5IiksDQogICAgbmFtZSA9ICJQbGFuZXRhcnkgTWFzcyAoTUp1cCkiDQogICkgKw0KICAjIFJlbW92ZSBncmlkIGFuZCBheGlzIGVsZW1lbnRzDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwNCiAgICBsZWdlbmQuYm94ID0gImhvcml6b250YWwiLA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpDQogICkgKw0KICBnZ3RpdGxlKCJFeG9wbGFuZXQgRGlzdHJpYnV0aW9uIikNCmBgYA0KDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocGxvdGx5KQ0KDQojIENyZWF0ZSBhIG5ldyBjb2x1bW4gdG8gZGlzdGluZ3Vpc2ggS2VwbGVyIGV4b3BsYW5ldHMNCmV4b3BsYW5ldHNfM2QgPC0gZXhvcGxhbmV0cyAlPiUNCiAgbXV0YXRlKA0KICAgIHJhX3JhZCA9IHJhICogcGkgLyAxODAsICAgIyBDb252ZXJ0IFJBIGZyb20gZGVncmVlcyB0byByYWRpYW5zDQogICAgZGVjX3JhZCA9IGRlYyAqIHBpIC8gMTgwLCAjIENvbnZlcnQgRGVjIGZyb20gZGVncmVlcyB0byByYWRpYW5zDQogICAgeCA9IGNvcyhkZWNfcmFkKSAqIGNvcyhyYV9yYWQpLCAjIENvbnZlcnQgdG8gQ2FydGVzaWFuIGNvb3JkaW5hdGVzDQogICAgeSA9IGNvcyhkZWNfcmFkKSAqIHNpbihyYV9yYWQpLA0KICAgIHogPSBzaW4oZGVjX3JhZCksDQogICAgY29sb3IgPSBjYXNlX3doZW4oICAjIENyZWF0ZSBhIGNvbHVtbiBmb3IgcmVkIHdoZW4ga2VwbGVyLCBibHVlIG90aGVyd2lzZQ0KICAgICAgc3RyX2RldGVjdChwYXN0ZShuYW1lLCBhbHRlcm5hdGVfbmFtZXMpLCByZWdleCgia2VwbGVyfGtvaSIsIGlnbm9yZV9jYXNlID0gVFJVRSkpIH4gIktlcGxlciIsDQogICAgICAjIGlmIGl0J3MgZnJlZSBmbG9hdGluZyAoc3Rhcl9uYW1lIGlzIE5BKQ0KICAgICAgc3Rhcl9uYW1lICU+JSBpcy5uYSgpIH4gIkZyZWUgRmxvYXRpbmciLA0KICAgICAgVFJVRSB+ICJPdGhlciINCiAgICApLA0KICAgIGhvdmVyX3RleHQgPSBwYXN0ZSgiTmFtZTogIiwgbmFtZSksICMgQ3JlYXRlIGN1c3RvbSBob3ZlciB0ZXh0IHdpdGggdGhlIG5hbWUgb2YgdGhlIGV4b3BsYW5ldA0KICAgIHNjYWxlZF94ID0geCAqICgxIC8gc3Rhcl9kaXN0YW5jZSksICAjIEFkanVzdCB4IGNvb3JkaW5hdGUgYnkgc3RhciBkaXN0YW5jZSAoY2xvc2VyID0gY2xvc2VyIHRvIGNlbnRlcikNCiAgICBzY2FsZWRfeSA9IHkgKiAoMSAvIHN0YXJfZGlzdGFuY2UpLCAgIyBBZGp1c3QgeSBjb29yZGluYXRlIHNpbWlsYXJseQ0KICAgIHNjYWxlZF96ID0geiAqICgxIC8gc3Rhcl9kaXN0YW5jZSkgICAjIEFkanVzdCB6IGNvb3JkaW5hdGUgc2ltaWxhcmx5DQogICkNCg0KIyBEZWZpbmUgc3RlcHMgZm9yIG9wYWNpdHkgc2xpZGVyDQpzdGVwcyA8LSBsaXN0KA0KICBsaXN0KGFyZ3MgPSBsaXN0KCJtYXJrZXIub3BhY2l0eSIsIDAuMCksIGxhYmVsID0gIjAuMCIsIG1ldGhvZCA9ICJyZXN0eWxlIiksDQogIGxpc3QoYXJncyA9IGxpc3QoIm1hcmtlci5vcGFjaXR5IiwgMC4xKSwgbGFiZWwgPSAiMC4xIiwgbWV0aG9kID0gInJlc3R5bGUiKSwNCiAgbGlzdChhcmdzID0gbGlzdCgibWFya2VyLm9wYWNpdHkiLCAwLjIpLCBsYWJlbCA9ICIwLjIiLCBtZXRob2QgPSAicmVzdHlsZSIpLA0KICBsaXN0KGFyZ3MgPSBsaXN0KCJtYXJrZXIub3BhY2l0eSIsIDAuMyksIGxhYmVsID0gIjAuMyIsIG1ldGhvZCA9ICJyZXN0eWxlIiksDQogIGxpc3QoYXJncyA9IGxpc3QoIm1hcmtlci5vcGFjaXR5IiwgMC40KSwgbGFiZWwgPSAiMC40IiwgbWV0aG9kID0gInJlc3R5bGUiKSwNCiAgbGlzdChhcmdzID0gbGlzdCgibWFya2VyLm9wYWNpdHkiLCAwLjUpLCBsYWJlbCA9ICIwLjUiLCBtZXRob2QgPSAicmVzdHlsZSIpLA0KICBsaXN0KGFyZ3MgPSBsaXN0KCJtYXJrZXIub3BhY2l0eSIsIDAuNiksIGxhYmVsID0gIjAuNiIsIG1ldGhvZCA9ICJyZXN0eWxlIiksDQogIGxpc3QoYXJncyA9IGxpc3QoIm1hcmtlci5vcGFjaXR5IiwgMC43KSwgbGFiZWwgPSAiMC43IiwgbWV0aG9kID0gInJlc3R5bGUiKSwNCiAgbGlzdChhcmdzID0gbGlzdCgibWFya2VyLm9wYWNpdHkiLCAwLjgpLCBsYWJlbCA9ICIwLjgiLCBtZXRob2QgPSAicmVzdHlsZSIpLA0KICBsaXN0KGFyZ3MgPSBsaXN0KCJtYXJrZXIub3BhY2l0eSIsIDAuOSksIGxhYmVsID0gIjAuOSIsIG1ldGhvZCA9ICJyZXN0eWxlIiksDQogIGxpc3QoYXJncyA9IGxpc3QoIm1hcmtlci5vcGFjaXR5IiwgMS4wKSwgbGFiZWwgPSAiMS4wIiwgbWV0aG9kID0gInJlc3R5bGUiKQ0KKQ0KDQojIENyZWF0ZSBhbiBpbnRlcmFjdGl2ZSAzRCBzY2F0dGVyIHBsb3Qgd2l0aCBwbG90bHkNCmZpZyA8LSBwbG90X2x5KA0KICBkYXRhID0gZXhvcGxhbmV0c18zZCwNCiAgeCA9IH5zY2FsZWRfeCwNCiAgeSA9IH5zY2FsZWRfeSwNCiAgeiA9IH5zY2FsZWRfeiwNCiAgY29sb3IgPSB+Y29sb3IsICAjIFVzZSB0aGUga2VwbGVyX2hpZ2hsaWdodCBjb2x1bW4gZm9yIGNvbG9yIG1hcHBpbmcNCiAgY29sb3JzID0gYygiT3RoZXIiID0gInJlZCIsICJLZXBsZXIiID0gImJsdWUiLCAiRnJlZSBGbG9hdGluZyIgPSAiZ3JlZW4iKSwNCiAgdGV4dCA9IH5ob3Zlcl90ZXh0LCAjIFNob3cgdGhlIG5hbWUgb2YgdGhlIGV4b3BsYW5ldCBvbiBob3Zlcg0KICB0eXBlID0gInNjYXR0ZXIzZCIsDQogIG1vZGUgPSAibWFya2VycyIsDQogIG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDIsIG9wYWNpdHkgPSAwLjcpLCAjIERlZmF1bHQgb3BhY2l0eQ0KICBzaG93bGVnZW5kID0gVFJVRQ0KKQ0KDQojIEFkZCBsYXlvdXQgd2l0aCBhIHNsaWRlciBmb3Igb3BhY2l0eQ0KZmlnIDwtIGZpZyAlPiUgbGF5b3V0KA0KICB0aXRsZSA9ICIzRCBTa3kgTWFwIG9mIEV4b3BsYW5ldHMgKEtlcGxlciBIaWdobGlnaHRlZCkiLA0KICBzY2VuZSA9IGxpc3QoDQogICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIlgiKSwNCiAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiWSIpLA0KICAgIHpheGlzID0gbGlzdCh0aXRsZSA9ICJaIikNCiAgKSwNCiAgc2xpZGVycyA9IGxpc3QoDQogICAgbGlzdCgNCiAgICAgIGFjdGl2ZSA9IDEsICAjIFNldCB0aGUgZGVmYXVsdCBvcGFjaXR5IHZhbHVlIHRvIDEuMCAoZnVsbHkgb3BhcXVlKQ0KICAgICAgY3VycmVudHZhbHVlID0gbGlzdCgNCiAgICAgICAgcHJlZml4ID0gIk9wYWNpdHk6ICIsDQogICAgICAgIGZvbnQgPSBsaXN0KHNpemUgPSAxNSkNCiAgICAgICksDQogICAgICBwYWQgPSBsaXN0KHQgPSA2MCksDQogICAgICBzdGVwcyA9IHN0ZXBzICAjIFVzZSB0aGUgc3RlcHMgZGVmaW5lZCBlYXJsaWVyIGZvciB0aGUgb3BhY2l0eSBzbGlkZXINCiAgICApDQogICkNCikNCg0KZmlnDQoNCg0KYGBgDQoNCg0KDQpgYGB7cn0NCmV4b3BsYW5ldHMgJT4lIG5hbWVzKCkNCmBgYA0KDQpgYGB7cn0NCiMgY2hlY2sgaG93IG1hbnkgYXJlIG1pc3NpbmcNCmV4b3BsYW5ldHMgJT4lIA0KICBzZWxlY3QocmEsIGRlYywgYW5ndWxhcl9kaXN0YW5jZSkgJT4lIA0KICBtdXRhdGUocmEgPSByYSAlPiUgaXMubmEoKSwgZGVjID0gZGVjICU+JSBpcy5uYSgpLCBhbmd1bGFyX2Rpc3RhbmNlID0gYW5ndWxhcl9kaXN0YW5jZSAlPiUgaXMubmEoKSkgJT4lDQogIHN1bW1hcmlzZV9hbGwobWVhbikgJT4lDQogIGdhdGhlcihrZXk9ImNvbHVtbiIsIHZhbHVlPSJwZXJjZW50YWdlIikNCmBgYA0KDQoNCmBgYHtyfQ0KIyBjaGVjayB3aGljaCBvbmVzIGRvbnQgaGF2ZSByYQ0KZXhvcGxhbmV0cyAlPiUgDQogIGZpbHRlcihyYSAlPiUgaXMubmEoKSkNCmBgYA0KDQpgYGB7cn0NCiMgY2hlY2sgb3V0IGFsdGVybmF0ZSBuYW1lcw0KZXhvcGxhbmV0cyAlPiUgDQogIHNlbGVjdChuYW1lLCBhbHRlcm5hdGVfbmFtZXMpICU+JSANCiAgZmlsdGVyKGFsdGVybmF0ZV9uYW1lcyAlPiUgc3RyX2xlbmd0aCgpID4gMCkNCg0KYGBgDQoNCmBgYHtyfQ0KZXhvcGxhbmV0cyAlPiUgDQogIHRhYnlsKHB1YmxpY2F0aW9uKQ0KYGBgDQoNCg0KYGBge3J9DQojIHJlbW92ZSBhbnkgY29sdW1uIHdpdGggZXJyb3IgaW4gdGhlIG5hbWUNCmV4b3BsYW5ldHNfciA8LSBleG9wbGFuZXRzICU+JSANCiAgc2VsZWN0KC1jb250YWlucygiZXJyb3IiKSkgJT4lIA0KICBzZWxlY3QoLXBsYW5ldF9zdGF0dXMsIC11cGRhdGVkLCAtYWx0ZXJuYXRlX25hbWVzLCAtcHVibGljYXRpb24pICU+JSAjIHVzZWxlc3MNCiAgc2VsZWN0KC1ob3RfcG9pbnRfbG9uLCApICMgdG9vIG1hbnkgbWlzc2luZ3MNCmV4b3BsYW5ldHNfciAlPiUgbmFtZXMNCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoPTIwLCBmaWcuaGVpZ2h0PTEwfQ0KbGlicmFyeSh2aXNkYXQpDQp2aXNfZGF0KGV4b3BsYW5ldHNfcikNCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoPTIwLCBmaWcuaGVpZ2h0PTEwfQ0KdmlzX21pc3MoZXhvcGxhbmV0c19yLCBzb3J0X21pc3MgPSBULCBjbHVzdGVyID0gVCkNCmBgYA0KDQoNCiMgZGV0ZWN0aW9uIHR5cGUNCmBgYHtyfQ0KZXhvcGxhbmV0cyAlPiUgDQogIHRhYnlsKCJkZXRlY3Rpb25fdHlwZSIpICU+JSANCiAgYXJyYW5nZSgtbikNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoZmFzdER1bW1pZXMpDQpleG9wbGFuZXRzX3JkIDwtIGV4b3BsYW5ldHNfciAlPiUgDQogIGR1bW15X2NvbHMoc2VsZWN0X2NvbHVtbnMgPSAiZGV0ZWN0aW9uX3R5cGUiLCBzcGxpdCA9ICIsICIpICU+JSANCiAgIyBtYWtlIHRoZW0gYm9vbHMNCiAgbXV0YXRlX2F0KHZhcnMoc3RhcnRzX3dpdGgoImRldGVjdGlvbl90eXBlXyIpKSwgYXMubG9naWNhbCkNCmV4b3BsYW5ldHNfcmQgJT4lIHNlbGVjdChzdGFydHNfd2l0aCgiZGV0ZWN0aW9uX3R5cGUiKSkgJT4lIA0KICB1bmlxdWUNCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTIwfQ0KbGlicmFyeShuYW5pYXIpDQpleG9wbGFuZXRzX3JkICU+JQ0KICBncm91cF9ieShgZGV0ZWN0aW9uX3R5cGVfUHJpbWFyeSBUcmFuc2l0YCkgJT4lIA0KICBtaXNzX3Zhcl9zdW1tYXJ5KCkgJT4lIA0KICBhcnJhbmdlKHZhcmlhYmxlKSAlPiUgDQogIGZpbHRlcih2YXJpYWJsZSAlPiUgc3RyX2RldGVjdCgiZGV0ZWN0aW9uX3R5cGUiLCBuZWdhdGUgPSBUKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSB2YXJpYWJsZSwgeSA9IHBjdF9taXNzLCBmaWxsID0gYGRldGVjdGlvbl90eXBlX1ByaW1hcnkgVHJhbnNpdGApKSArDQogIGdlb21fY29sKHBvc2l0aW9uPSJkb2RnZSIpICsNCiAgY29vcmRfZmxpcCgpIA0KYGBgDQoNCg0KIyMgS2VwbGVyDQoNCmBgYHtyfQ0KIyBmaWx0ZXIgYnkgdGhlIGtlcGxlcg0KZXhvcGxhbmV0cyAlPiUgDQogIGZpbHRlcihuYW1lICU+JSBzdHJfbGlrZSgiJUtlcGxlciUiKSkgJT4lIA0KICB0YWJ5bCgiZGV0ZWN0aW9uX3R5cGUiKQ0KYGBgDQoNCmBgYHtyfQ0KIyBjaGVjayBvdGhlcg0KZXhvcGxhbmV0cyAlPiUgDQogIGZpbHRlcihkZXRlY3Rpb25fdHlwZSA9PSAiT3RoZXIiKQ0KYGBgDQoNCg0KYGBge3J9DQoNCmBgYA0KDQo=